home *** CD-ROM | disk | FTP | other *** search
- /*******************************************************
- * *
- * data.c contains most of the routines for dealing with the actual structure of the *
- * dataState records. Although currently these structures may be manipulated *
- * by other routines, this may change. *
- * *
- *******************************************************/
-
- #include "main.h"
-
- extern Pattern dragPat,
- *getAnts();
- extern long timer();
- extern int isBackground;
- extern char *NewPtrClear();
-
- dataHandle currentData = NULL;
- long defaultCycleLength = 36; /* should be read from a string at startup */
-
- /*******************************************************
- * *
- * LinkedInsert and LinkedDelete maintain a doubly linked list of dataStates. This *
- * list is refered into by the refCons of the parent windows of the dataStates and *
- * by the global currentData, which points to the one currently being considered *
- * for stepping or copying. *
- * *
- *******************************************************/
-
- dataHandle linkedInsert( head, new )
- dataHandle head, new;
- {
- if( head )
- {
- (**new).next = head;
- (**new).prev = (**head).prev;
- (**head).prev = new;
- (**(**new).prev).next = new;
- }
- else (**new).next = (**new).prev = new;
- return( new );
- }
-
- dataHandle linkedDelete( old )
- dataHandle old;
- {
- if( (**old).next != old )
- {
- (**(**old).next).prev = (**old).prev;
- (**(**old).prev).next = (**old).next;
- return( (**old).next );
- }
- return( NULL );
- }
-
- /*******************************************************
- * *
- * DisposeData is called when a window is closed to dispose of all of the storage *
- * associated with a dataState. This can be quite a lot, with up to five bitmaps *
- * and several regions. *
- * *
- *******************************************************/
-
- disposeData( theDataHand )
- dataHandle theDataHand;
- {
- dataPtr theData;
- int i;
-
- HLock( theDataHand );
- theData = *theDataHand;
- if( theData->state ) --isBackground;
- for( i = 0; i < theData->planes; ++i )
- DisposPtr( theData->bases[ i ] );
- DisposPtr( theData->allBits.baseAddr );
- DisposeRgn( theData->selRgn );
- if( theData->isSelect )
- DisposPtr( theData->selBits.baseAddr );
- if( theData->cycleFlags != cycleNone && theData->cycleBase )
- DisposHandle( theData->cycleBase );
- currentData = linkedDelete( theDataHand );
- DisposHandle( theDataHand );
- }
-
- /*******************************************************
- * *
- * NewData assumes that the window has already been set as the current port *
- * and all that, and creates a new dataState record, pointing the refCon of the *
- * parent window at it. All fields are initialized - on the first updateEvent the *
- * (zero) contents will be rendered and displayed. *
- * *
- *******************************************************/
-
- newData( theWindow, theFont, flags )
- WindowPtr theWindow;
- dataFontPtr theFont;
- int flags;
- {
- dataHandle theDataHand;
- dataPtr theData;
- int i, errno;
-
- theDataHand = (dataHandle)NewHandle(( long )sizeof( dataState ));
- if( errno = MemError() ) hardPanic( errno, memPanic );
- HLock( theDataHand );
- theData = *theDataHand;
- theData->parent = theWindow;
- SetWRefCon( theWindow, theDataHand );
- currentData = linkedInsert( currentData, theDataHand );
- theData->theFont = *theFont;
- theData->state = dataStopped;
- theData->planes = 2;
- theData->flags = flags;
- theData->changed = timer();
- theData->generation = 0;
- theData->undoGeneration = 0;
- theData->undoFlags = undoNone;
- theData->partDone = 0;
- theData->isSelect = 0;
- theData->selActive = 0;
- theData->lastGenWidth = 0; /* was missing! - big bug… */
- theData->cycleLength = defaultCycleLength;
- theData->cycleFlags = cycleNone;
- theData->selRgn = NewRgn();
- if( errno = MemError() ) hardPanic( errno, memPanic );
-
- setDataBounds( theData );
- for( i = 0; i < theData->planes; ++i ) {
- theData->bases[ i ] = NewPtrClear( theData->planeSize );
- if( errno = MemError() ) hardPanic( errno, memPanic );
- }
- theData->offBits.baseAddr = theData->bases[0];
-
- HUnlock( theDataHand );
- }
-
- /*******************************************************
- * *
- * StopData is called both by the 'stop' menu command and by drawing routines *
- * which require a non-changing bitmap to work with. The force flag forces any *
- * pending drawing to be completed. The previous state is returned, so that the *
- * data may be restarted. *
- * *
- *******************************************************/
-
- stopData( theData, force )
- dataPtr theData;
- int force;
- {
- int oldState;
-
- oldState = theData->state;
- if( oldState != dataStopped )
- if( theData->partDone < -1 && force == dontForceStop )
- theData->state = dataStepping;
- else {
- if( theData->partDone < -1 )
- finishCopy( theData );
- theData->state = dataStopped;
- if( oldState != dataStopped )
- --isBackground;
- if( force == forceStop ) theData->partDone = 0;
- }
- return( oldState );
- }
-
- /*******************************************************
- * *
- * restartData is used to restore the previous state of data that has been stopped *
- * by a drawing routine, using stopData. *
- * *
- *******************************************************/
-
- restartData( theData, oldState )
- dataPtr theData;
- int oldState;
- {
- if( oldState ) ++isBackground;
- theData->state = oldState;
- }
-
- madeChange( theData )
- dataPtr theData;
- {
- theData->changed = timer();
- theData->undoGeneration = theData->generation;
- theData->undoFlags |= undoData;
- theData->allBitsState |= bitsBadData + bitsBadGen;
- }
-
- swapPlane( theData )
- dataPtr theData;
- {
- theData->offBits.baseAddr = theData->bases[1];
- theData->bases[1] = theData->bases[0];
- theData->bases[0] = theData->offBits.baseAddr;
- theData->undoGeneration = theData->generation;
- }
-
- /*******************************************************
- * *
- * reshapeData re-allocates memory for the data from scratch, and copies the *
- * previous state into the new space. The bounds are taken from the window *
- * bounds of the data's parent, using setDataBounds. If cycle-detection is on, the *
- * new data bits are copied into a new cycle-detection bitmap, and the counter *
- * is started over. *
- * *
- *******************************************************/
-
- reshapeData( theDataHand )
- dataHandle theDataHand;
- {
- BitMap oldBits, *newBits;
- Rect bounds;
- dataPtr theData;
- long oldSize;
- int i, errno;
-
- HLock( theDataHand );
- theData = *theDataHand;
- oldBits = theData->offBits;
- oldSize = theData->planeSize;
- DisposPtr( theData->allBits.baseAddr );
- setDataBounds( theData );
- newBits = &( theData->offBits );
- SectRect( &( oldBits.bounds ), &( newBits->bounds ), &bounds );
- SectRect( &( theData->parent->portRect ), &bounds, &bounds );
- for( i = 0; i < theData->planes; ++i ) {
- oldBits.baseAddr = theData->bases[ i ];
- newBits->baseAddr = theData->bases[ i ] = NewPtrClear( theData->planeSize );
- if( errno = MemError() ) hardPanic( errno, memPanic );
- CopyBig( &oldBits, newBits, &bounds, &bounds, srcCopy, NULL );
- DisposPtr( oldBits.baseAddr );
- }
- theData->partDone = 0;
- newBits->baseAddr = theData->bases[ 0 ];
- if( theData->cycleFlags != cycleNone ) {
- if( theData->cycleBase )
- DisposHandle( theData->cycleBase );
- /* error in this allocation will cause no problems - just postpone detection */
- PtrToHand( theData->bases[ 0 ], &theData->cycleBase, theData->planeSize );
- if( theData->cycleBase ) HPurge( theData->cycleBase );
- theData->cycleGeneration = theData->generation;
- theData->cycleFitLength = theData->cycleLength;
- }
- HUnlock( theDataHand );
- }
-
- /*******************************************************
- * *
- * These currently simply re-allocate the memory used by the data. They could *
- * be updated to test for the case that the same amount of memory is needed as *
- * before, or this change could be made to the reshapeData routine, perhaps more *
- * productively. *
- * *
- *******************************************************/
-
- shiftData( theDataHand )
- dataHandle theDataHand;
- {
- reshapeData( theDataHand );
- }
-
- sizeData( theDataHand )
- dataHandle theDataHand;
- {
- reshapeData( theDataHand );
- }
-
- /*******************************************************
- * *
- * setDataBounds resets the bounds, rowBytes, and planeSize from scratch. *
- * There used to be a special case for new, shift, and size, but this puts it all in *
- * one place, so it can be updated easily. *
- * *
- *******************************************************/
-
- setDataBounds( theData )
- dataPtr theData;
- {
- WindowPtr theWindow = theData->parent;
- BitMap *theBits;
- long planeSize;
- int h, w, rowBytes, ldiff, errno;
-
- theBits = &( theData->offBits );
- theData->dataRect = theWindow->portRect;
- if( theData->flags & dataStatLine )
- theData->dataRect.top += theData->theFont.topSpace;
- theBits->bounds = theData->dataRect;
- ldiff = ( theData->dataRect.left - theWindow->portBits.bounds.left ) & 15;
- theBits->bounds.left -= ldiff ? ldiff : 16;
- w = theBits->bounds.right - theBits->bounds.left;
- rowBytes = (( w + 32 ) >> 3 ) & longMask;
- theBits->rowBytes = rowBytes;
- h = theBits->bounds.bottom - theBits->bounds.top;
- theData->planeSize = (long)h * rowBytes + 16;
-
- theData->allBits.bounds = theBits->bounds;
- theData->allBits.bounds.top = theWindow->portRect.top;
- theData->allBits.rowBytes = rowBytes;
- h = theData->allBits.bounds.bottom - theData->allBits.bounds.top;
- theData->allBits.baseAddr = NewPtrClear(( long )h * rowBytes );
- if( errno = MemError() ) hardPanic( errno, memPanic );
- theData->allBitsState = bitsBadData | bitsBadFrame | bitsBadSel | bitsBadGen;
- }
-
- /*******************************************************
- * *
- * CopyDisplay draws the gray onto the bitmap to be copied, clips to the current *
- * menuRgn, and copies the bounds rectangle from the source bitmap to thePort. *
- * *
- *******************************************************/
-
- copyDisplay( source, bounds, mask, gray )
- BitMap *source;
- Rect *bounds;
- RgnHandle mask, gray;
- {
- RgnHandle saveClip;
-
- saveClip = NewRgn();
- doMenuClip( saveClip );
- drawGray( source, bounds, gray );
- CopyBig( source, &( thePort->portBits ), bounds, bounds, srcCopy, mask );
- drawGray( source, bounds, gray );
- SetClip( saveClip );
- DisposeRgn( saveClip );
- }
-
- /*******************************************************
- * *
- * *
- *******************************************************/
-
- displayData( theData, toDraw, gray )
- dataPtr theData;
- int toDraw;
- RgnHandle gray;
- {
- Rect bounds;
- RgnHandle maskRgn;
-
- if( EmptyRgn((( WindowPeek )( theData->parent ))->updateRgn )) {
- if( theData->generation != theData->lastGeneration && ( toDraw & bitsBadGen ) && ( theData->flags & dataStatLine )) {
- updateGen( theData, &bounds );
- copyDisplay( &( theData->allBits ), &bounds, NULL, gray );
- }
- if( toDraw & bitsBadData ) {
- maskRgn = NewRgn();
- RectRgn( maskRgn, &( theData->dataRect ));
- if( theData->isSelect )
- DiffRgn( maskRgn, theData->selRgn, maskRgn );
- copyDisplay( &( theData->offBits ), &( theData->dataRect ), maskRgn, gray );
- DisposeRgn( maskRgn );
- }
- if( toDraw & bitsBadSel && theData->isSelect ) {
- maskRgn = NewRgn();
- CopyRgn( theData->selRgn, maskRgn );
- if( theData->selActive ) InsetRgn( maskRgn, 1, 1 );
- copyDisplay( &( theData->selBits ), &( theData->selBits.bounds ), maskRgn, gray );
- DisposeRgn( maskRgn );
- }
- theData->allBitsState |= toDraw;
- } else {
- fixAllBits( theData );
- BeginUpdate( theData->parent );
- EndUpdate( theData->parent );
- copyDisplay( &( theData->allBits ), &( theData->parent->portRect ), NULL, gray );
- }
- }
-
- updateGen( theData, bounds )
- dataPtr theData;
- Rect *bounds;
- {
- char theString[ pasStrLen ], *numStart;
- BitMap saveBits;
- RgnHandle saveVis;
- WindowPtr theWindow;
- int nextWidth, modWidth, genStart;
-
- saveVis = NewRgn();
- theWindow = theData->parent;
- CopyRgn( theWindow->visRgn, saveVis );
- setBigRgn( theWindow->visRgn );
- saveBits = thePort->portBits;
- SetPortBits( &( theData->allBits ));
-
- displayNumPas( theData->generation, theString + 255, &numStart );
- nextWidth = StringWidth( numStart );
- modWidth = max( nextWidth, theData->lastGenWidth );
- theData->lastGenWidth = nextWidth;
- theData->lastGeneration = theData->generation;
-
- genStart = theData->theFont.genStart;
- SetRect( bounds, genStart, 0, genStart + modWidth, theData->theFont.topSpace - 1 );
- EraseRect( bounds );
- MoveTo( genStart, theData->theFont.topStart );
- DrawString( numStart );
- theData->allBitsState &= -1 - bitsBadGen;
-
- SetPortBits( &saveBits );
- CopyRgn( saveVis, theWindow->visRgn );
- DisposeRgn( saveVis );
- }
-
- fixAllBits( theData )
- dataPtr theData;
- {
- char theString[ pasStrLen ], *numStart;
- PenState savePen;
- BitMap saveBits;
- Rect *bounds;
- RgnHandle saveVis, tempRgn;
- WindowPtr theWindow;
- int state;
-
- saveVis = NewRgn();
- theWindow = theData->parent;
- CopyRgn( theWindow->visRgn, saveVis );
- setBigRgn( theWindow->visRgn );
- saveBits = thePort->portBits;
- SetPortBits( &( theData->allBits ));
- GetPenState( &savePen );
-
- tempRgn = NewRgn();
- RectRgn( tempRgn, &( theData->dataRect ));
- state = theData->allBitsState;
- if( theData->isSelect )
- {
- bounds = &( theData->selBits.bounds );
- if(( state & bitsBadSel ) || (( state & bitsBadAnts ) && ( theData->selActive == 0 )))
- CopyBig( &( theData->selBits ), &( theData->allBits ), bounds, bounds, srcCopy, theData->selRgn );
- if( theData->selActive && ( state & ( bitsBadAnts + bitsBadSel )))
- {
- PenMode( patCopy );
- PenPat( getAnts( theData->antSkew ));
- FrameRgn( theData->selRgn );
- }
- if( state & bitsBadData )
- DiffRgn( tempRgn, theData->selRgn, tempRgn );
- }
- if( state & bitsBadData )
- {
- bounds = &( theData->dataRect );
- CopyBig( &( theData->offBits ), &( theData->allBits ), bounds, bounds, srcCopy, tempRgn );
- }
- if(( state & bitsBadFrame ) && ( theData->flags & dataStatLine ))
- {
- PenPat( black );
- PenMode( patOr );
- MoveTo( 0, theData->theFont.topSpace - 1 );
- Line( thePort->portRect.right, 0 );
- MoveTo( leftMargin, theData->theFont.topStart );
- GetIndString( theString, statStrings, genStr );
- DrawString( theString );
- }
- if(( state & bitsBadGen ) && ( theData->flags & dataStatLine ))
- {
- displayNumPas( theData->generation, theString + pasStrLen - 1, &numStart );
- MoveTo( theData->theFont.genStart, theData->theFont.topStart );
- DrawString( numStart );
- }
- theData->allBitsState = 0;
-
- DisposeRgn( tempRgn );
- SetPenState( &savePen );
- SetPortBits( &saveBits );
- CopyRgn( saveVis, theWindow->visRgn );
- DisposeRgn( saveVis );
- }
-
- /*******************************************************
- * *
- * drawGray draws a gray region onto the given bitmap, USING THEPORT. That *
- * is, you have to arrange for the current port to be set up, but don't need to *
- * worry about changing portBits. When it returns, all is as it was before. The *
- * gray is Xor-ed on, so a second call after using the bitmap will return to the *
- * original state. The origin is adjusted so that the dragPat is drawn with the *
- * same shift as it would be in the original bitmap, and then adjusted back. *
- * *
- *******************************************************/
-
- drawGray( whichBits, bounds, theGray )
- BitMap *whichBits;
- Rect *bounds;
- RgnHandle theGray;
- {
- GrafPort tempPort;
- GrafPtr savePort;
- Point off;
-
- if( theGray )
- {
- off = topLeft( thePort->portBits.bounds );
- GetPort( &savePort );
- OpenPort( &tempPort );
- SetPortBits( whichBits );
- thePort->portRect = savePort->portRect;
- PenMode( notPatXor );
- PenPat( dragPat );
- SetOrigin( -off.h, -off.v );
- ClipRect( bounds );
- OffsetRgn( thePort->clipRgn, -off.h, -off.v );
- CopyRgn( thePort->clipRgn, thePort->visRgn );
- PaintRgn( theGray );
- SetPort( savePort );
- ClosePort( &tempPort );
- }
- }